////////////////////////////////////////////////////////////////////////////////
/*! \file
 * \brief The interface file for the MythDynamic library.
 *
 * The MythDynamic library allows a computer program to, at run time, load a
 * library, retrieve the addresses of functions and variables contained in the
 * library, execute those functions or access those variables and unload the
 * library from memory. This allows a computer program to discover libraries and
 * potentially gain additional functionality.
 *
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.1.1
 * \copyright GNU Lesser General Public License v3
 */
////////////////////////////////////////////////////////////////////////////////

#ifndef __MYTH_DYNAMIC_HPP_INCLUDED__
#define __MYTH_DYNAMIC_HPP_INCLUDED__

////////////////////////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////////////////////////
#include "Myth.hpp"

////////////////////////////////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////////////////////////////////
#if (!defined _MYTH_DYNAMIC_EXTENSION_)
    #if ((!defined _MYTH_DYNAMIC_STATIC_LIBRARY_) && \
        (!defined _MYTH_DYNAMIC_DYNAMIC_LIBRARY_))
        #error Please define which version of the library you are using.
    #endif

    #ifdef _MYTH_WINDOWS_
        #ifdef _MYTH_DYNAMIC_STATIC_LIBRARY_
            #define _MYTH_DYNAMIC_API_
        #endif // _MYTH_DYNAMIC_STATIC_LIBRARY_

        #ifdef _MYTH_DYNAMIC_LIBRARY_
            #ifdef _MYTH_DYNAMIC_EXPORT_
                #define _MYTH_DYNAMIC_API_ __declspec(dllexport)
            #else
                #define _MYTH_DYNAMIC_API_ __declspec(dllimport)
            #endif // _MYTH_DYNAMIC_EXPORT_
        #endif // _MYTH_DYNAMIC_DYNAMIC_LIBRARY_
    #endif // _MYTH_WINDOWS_

    #ifdef _MYTH_LINUX_
        #define _MYTH_DYNAMIC_API_
    #endif // _MYTH_LINUX_
#endif // _MYTH_DYNAMIC_EXTENSION_

namespace Myth
{
////////////////////////////////////////////////////////////////////////////////
//! The namespace of the MythDynamic library.
namespace Dynamic
{

////////////////////////////////////////////////////////////////////////////////
//! An interface providing access to dynamically loaded libraries.
/*!
 * This class acts as an abstraction-layer between different operating systems.
 * After you have loaded a library in the memory with create_dynamic_library()
 * or create_dynamic_self_reference() you can use this class to extract symbols
 * from it.
 *
 * Because this class is reference counted, you can easily share it across a
 * program. You must however make sure you don't use any symbols from the
 * library after it was unloaded. Doing so will either crash your program or
 * cause memory corruption.
 */
class _MYTH_DYNAMIC_API_ Library : public virtual ReferenceCounter
{
public:
    ////////////////////////////////////////////////////////////////////////////
    //! Searches for the specified symbol and returns it if found.
    /*!
     * \return A pointer to the found symbol or NULL if an error occured.
     *
     * \param[in] symbol_name The name of the symbol to retrieve.
     *
     * \param[out] error_message If this is non-null and an error occured, this
     *                           will contain the error message from the
     *                           operating system.
     */
    virtual void* get_symbol(const std::string& symbol_name,
                             std::string*       error_message = 0) = 0;
};

#if (!defined _MYTH_DYNAMIC_EXTENSION_)

    ////////////////////////////////////////////////////////////////////////////
    //! Try to load the library in memory and return a handle to it on success.
    /*!
     * With this function you can ask the operation system to load a library and
     * give you access to it. This can, for example, be used to create a plugin
     * system.
     *
     * \return A pointer to the newly created library object or NULL if an error
     *         occured.
     *
     * \param[in] file_name The name of the library you want to open. This must
     *                      be a null terminated string of either the full path
     *                      to a library or the name of the requested library in
     *                      one of the system standard library folders.
     *
     * \param[out] error_message If this is non-null and an error occured, this
     *                           will contain the error message from the
     *                           operating system.
     */
    extern "C" _MYTH_DYNAMIC_API_ Library* _MYTH_CALL_CONV_ create_dynamic_library(const std::string&   file_name,
                                                                                   std::string*         error_message = 0);

    ////////////////////////////////////////////////////////////////////////////
    //! Returns a handle to the currently running executable.
    /*!
     * This function allows programmers to extract symbols from the currently
     * executing process. The resulting handle can be used in the same manner as
     * the result from create_dynamic_library().
     *
     * \return A handle to the currently running executable.
     */
    extern "C" _MYTH_DYNAMIC_API_ Library* _MYTH_CALL_CONV_ create_dynamic_self_reference(void);

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the version of the MythDynamic library.
    /*!
     * \return The version of the MythDynamic library.
     */
    extern "C" _MYTH_DYNAMIC_API_ uint32_t _MYTH_CALL_CONV_ get_myth_dynamic_version(void);

#endif // _MYTH_DYNAMIC_EXTENSION_

} // namespace Dynamic
} // namespace Myth

#endif // __MYTH_DYNAMIC_HPP_INCLUDED__
